Resolve Short URLs with Pythonista on iOS

Clean URLs

I don’t like it when third-party apps or services force me to share links to articles or webpages using their own custom shortened links. I understand the appeal of personalized short domains – after all, we tweet mcstr.net links with the @macstoriesnet account – as they can provide analytics to track clicks, can save characters, and, at least in theory, they “look cool”. However, I’ve been long considering the idea of dropping our mcstr.net links, but I think the issue is worse (and more annoying) for apps and services that don’t tweet links to their own content (like we do) but that override others’ links with different domains. An example is Pocket, which gives you the clean, original URL when you choose the “Copy Link” action from the sharing menu, but that instead returns pocket.co links when sending text to Drafts (which I do often). I’ve grown tired of this practice (in Pocket and other services), and I’ve put together a workflow based on a Python script that allows me to easily resolve short links without having to open the browser and tap on multiple menus.

As I briefly mentioned in a footnote in May, my problem with short URLs was that Flipboard’s “Flip It” bookmarklet can’t fetch URLs behind pocket.co links. In trying to minimize friction as much as possible, I wanted to have a solution that allowed me to send a link from Pocket to Drafts without having to hit “Copy Link” first; then, from Drafts I could launch an action to save a link in Flipboard, but in order to resolve the shortened link I’d have to put a script in the middle. The script I’ve created receives a URL, tries to fetch the real URL of a webpage, and returns a redirect-free URL that I can send to Flipboard, knowing that the service’s web interface will recognize it and add it to my magazine.

The script is short and I’m using it with Pythonista on iOS, but it can be tweaked with minor modifications and ported to OS X if you want to run it in apps like Keyboard Maestro or Alfred. In my workflow, when I’m done reading an article in Pocket, I tap “Send to Drafts”, then the “Clean URL” action, and in a matter of seconds I’m taken from Drafts, to Pythonista, then to Flipboard’s sharing page in Google Chrome, and, last, back to Pocket, where I can archive the article I just read and shared.

Script and quick demo video below.

import re
import string
import console
import urllib
import sys
import clipboard
import webbrowser

console.clear()

# Count arguments passed to script, if less than 2 run regex against clipboard
numArgs = len(sys.argv)

if numArgs == 2:
redirect = sys.argv[1]
elif numArgs ]+(?:\([\w\d]+\)|([^%s\s]|/)))'
pat = pat % re.escape(string.punctuation)

match = re.findall(pat, redirect)

if match:
for x in match:
console.show_activity()
# Get the first match without redirects
cleaned = urllib.urlopen(x[0]).geturl()
final = urllib.quote(cleaned, safe='')
clipboard.set(cleaned)
console.hide_activity()
webbrowser.open('googlechrome-x-callback://x-callback-url/open/?url=https%3A%2F%2Fshare.flipboard.com%2Fflipit%2Fload%3Fv%3D1.0%26url%3D' + final + '&x-success=pocket://&x-source=Pocket')
elif not match:
console.alert('No match found')

The script essentially relies on the geturl() method of urllib.urlopen() to follow all redirects of a link and return the real URL of a page. As written in the Python documentation:

The geturl() method returns the real URL of the page. In some cases, the HTTP server redirects a client to another URL. The urlopen() function handles this transparently, but in some cases the caller needs to know which URL the client was redirected to. The geturl() method can be used to get at this redirected URL.

Line 12 counts the arguments that have been passed to the script: if less than 2, the script assumes a link may be in the clipboard; if 2 arguments are found, sys.argv[1] is identified as the URL to fetch. I do this because I want to be able to send text from Drafts to Pythonista, and, as I detailed in my original review, Pythonista’s URL scheme supports arguments, which make it easy to set up the kind of check that I have in my script.

Clean URLs

You can launch this script from apps like Launch Center Pro or iCab, but here’s what my Drafts action looks like:

pythonista://CleanURL?action=run&argv=[[draft]]

Lines 21–22 use a regular expression by Peter Hansen (posted in reply to a question about Gruber’s regex in Python) that scans received text for a match; the match is, as you’d imagine, a web URL. Because Pocket sends both an article’s title and short link to Drafts on a single line, we can’t use Drafts’ line tags to easily separate the title from the URL, and the best way to do that is a regex that returns matches of a URL in a string. You can use any regex for matching URLs – Hansen’s worked fine for me and I like its simplicity.

Line 25 runs the regex with re.findall() and lines 27–37 contain the actual URL-fetching mechanism inside an if statement that checks whether there is a match in the first place. Line 31 gets the first match returned by re.findall, fetches its real URL, and percent-encodes it using urllib.quote with no default safe character. The system clipboard is then set to the newly-acquired URL on line 33.

Now, the script could be used like this (get a URL, fetch its real version, set it to the clipboard) without caring about Flipboard’s web interface at all. But because I do a lot of gaming-related reading in Pocket and I have a Flipboard magazine I try to update regularly, I added a line to the script that launches Google Chrome, opens the Flipboard sharing page, and passes the non-Pocket URL fetched by the script.

Clean URLs

Using the webbrowser module and Chrome’s callback system, the script launches Chrome, which will display the Flipboard magazine popup pre-filled with my URL and a custom back button that will take me back to Pocket once the URL has been added to Flipboard. A nice thing about Flipboard’s share UI is that it doesn’t navigate to another page when you add a URL, so the Pocket button will always remain visible.

I realize that not everyone may need a script that resolves a short link and returns the clean, original version; however, I still think it’s pretty incredible that I can run a Python script on my phone to save a few seconds every day, which add up to several minutes every year that I can spend doing better and more productive things than tapping on browser menus – such as spending more time at the beach with my girlfriend. I may not be as adventurous as Dr. Drang, solving a client’s problems with a Python program from a gas station parking lot, but, even from the comfort of my couch, I’m quite fond of the solution I’ve put together to more easily share Pocket links to Flipboard.